/*
 * SwingGraphics.cpp  0.4.0 / Nov 17, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "SwingGraphics.h"

// SwingGraphics :: Public Constructors. ---------------------------------------

/*!
 * \brief Constructs new SwingGraphics object.
 *
 * \param device the QPaintDevice
 */
SwingGraphics::SwingGraphics(QPaintDevice *device)
  : QPainter(device)
{
  Q_ASSERT(device);
}

/*!
 * \brief Constructs new SwingGraphics object.
 *
 * \param device the QPaintDevice
 * \param x the x coordinate of the clipping region
 * \param y the y coordinate of the clipping region
 * \param width the width of the clipping region
 * \param height the height of the clipping region
 */
SwingGraphics::SwingGraphics(QPaintDevice *device, jint x, jint y, jint width,
                             jint height)
  : QPainter(device)
{
  Q_ASSERT(device);
  setClipRect(x, y, width, height);
}

// SwingGraphics :: Public Member Functions. -----------------------------------

/*!
 * \brief Returns current color of the graphics.
 *
 * \return current color of the graphics
 */
jobject SwingGraphics::getColor()
{
  return QColorAdapter::toJColor(pen().color());
}

/*!
 * \brief Sets current color of the graphics.
 *
 * \param argb the argb value of the color
 */
void SwingGraphics::setColor(jint argb)
{
  QPen p = pen();
  p.setColor(QColorAdapter(argb));
  setPen(p);
}

/*!
 * \brief Returns current font of the graphics.
 *
 * \return current font of the graphics
 */
jobject SwingGraphics::getFont()
{
  return QFontAdapter::toJFont(font());
}

/*!
 * \brief Sets current font of the graphics.
 *
 * \param font the Swing font object
 */
void SwingGraphics::setFont(jobject font)
{
  if (font) {
    QPainter::setFont(*QFontAdapter::toQFont(font));
  } else {
    QPainter::setFont(QFont());
  }
}

/*!
 * \brief Sets linear gradient.
 *
 * \param x1 the x coordinate of the gradient's start point
 * \param y1 the y coordinate of the gradient's start point
 * \param argb1 the argb value of the first color
 * \param x2 the x coordinate of the gradient's end point
 * \param y2 the y coordinate of the gradient's end point
 * \param argb2 the argb value of the second color
 * \param cyclic \c true if the gradient is cyclic
 */
void SwingGraphics::setLinearGradient(jint x1, jint y1, jint argb1, jint x2,
                                      jint y2, jint argb2, jboolean cyclic)
{
  QLinearGradient linearGradient(x1, y1, x2, y2);
  if (cyclic) {
    linearGradient.setSpread(QGradient::ReflectSpread);
  }
  linearGradient.setColorAt(0, QColorAdapter(argb1));
  linearGradient.setColorAt(1, QColorAdapter(argb2));
  QBrush b(linearGradient);
  QPen p = pen();
  p.setBrush(b);
  setPen(p);
  setBrush(b);
}

/*!
 * \brief Sets texture gradient.
 *
 * \param image the patern image
 */
void SwingGraphics::setTextureGradient(QPixmap *image)
{
  if (image) {
    QBrush b(*image);
    QPen p = pen();
    p.setBrush(b);
    setPen(p);
    setBrush(b);
  }
}

/*!
 * \brief Sets basic stroke.
 *
 * \param width the stroke width
 * \param cap the stroke cap
 * \param join the stroke join
 * \param miterLimit the stroke miter limit
 * \param dash the stroke dash
 * \param dashPhase the stroke dash phase
 */
void SwingGraphics::setBasicStroke(jfloat width, jint cap, jint join,
                                   jfloat miterLimit, jfloatArray dash,
                                   jfloat dashPhase)
{
  Q_UNUSED(dashPhase); // dash pahse is not currently supported
  QPen p = pen();
  p.setWidthF(width);
  p.setCapStyle(PEN_CAP_STYLE[cap]);
  p.setJoinStyle(PEN_JOIN_STYLE[join]);
  p.setMiterLimit(miterLimit);
  if (dash) {
    jsize dashLenght = SWING_ENV->GetArrayLength(dash);
    float *dashArray = (float *)SWING_ENV->GetPrimitiveArrayCritical(dash, 0);
    QVector<qreal> dashes(dashLenght);
    for (int i = 0; i < dashLenght; i++) {
      dashes.append(dashArray[i]);
    }
    SWING_ENV->ReleasePrimitiveArrayCritical(dash, dashArray, JNI_ABORT);
    p.setDashPattern(dashes);
  } else {
    p.setStyle(Qt::SolidLine);
  }
  setPen(p);
}

/*!
 * \brief Pushes the state of the graphics.
 */
void SwingGraphics::push()
{
  // TODO: add stack state (like QPainter::QPainterState)
  end();
}

/*!
 * \brief Pops the state of the graphics.
 */
void SwingGraphics::pop()
{
  // TODO: use state stack
  begin(device());
}

/*!
 * \brief Pops the state of the graphics.
 *
 * \param imageData the image data
 * \param length the length of the image data
 * \param x the x coordinate of the image
 * \param y the y coordinate of the image
 */
void SwingGraphics::drawImage(jbyteArray imageData, jint length, jint x,
                              jint y)
{
  if (imageData) {
    QPixmap pixmap;
    uchar *bytes = (uchar *)SWING_ENV->GetPrimitiveArrayCritical(imageData, 0);
    bool loadSucceed = pixmap.loadFromData(bytes, length);
    SWING_ENV->ReleasePrimitiveArrayCritical(imageData, bytes, JNI_ABORT);
    if (loadSucceed) {
      drawPixmap(x, y, pixmap);
    }
  }
}

/*!
 * \brief Fills rectangle.
 *
 * \param x the x coordinate of the rectangle
 * \param y the y coordinate of the rectangle
 * \param w the width of the rectangle
 * \param h the height of the rectangle
 */
void SwingGraphics::fillRect(jint x, jint y, jint w, jint h)
{
  QBrush oldBrush = brush(); // TODO: const ?
  QPen oldPen = pen();
  QBrush b = oldBrush;
  b.setStyle(Qt::SolidPattern);
  b.setColor(oldPen.color());
  setBrush(b);
  setPen(Qt::NoPen);
  drawRect(x, y, w, h);
  setPen(oldPen);
  setBrush(oldBrush);
}

/*!
 * \brief Fills oval.
 *
 * \param x the x coordinate of the oval
 * \param y the y coordinate of the oval
 * \param w the width of the oval
 * \param h the height of the oval
 */
void SwingGraphics::fillOval(jint x, jint y, jint w, jint h)
{
  QBrush oldBrush = brush();
  QPen oldPen = pen();
  QBrush b = oldBrush;
  b.setStyle(Qt::SolidPattern);
  b.setColor(oldPen.color());
  setBrush(b);
  setPen(Qt::NoPen);
  drawEllipse(x, y, w, h);
  setPen(oldPen);
  setBrush(oldBrush);
}

// SwingGraphics ::Private Static Constant Data Members. -----------------------

const Qt::PenCapStyle SwingGraphics::PEN_CAP_STYLE[] = {
  Qt::FlatCap,
  Qt::RoundCap,
  Qt::SquareCap
};
const Qt::PenJoinStyle SwingGraphics::PEN_JOIN_STYLE[] = {
  Qt::MiterJoin,
  Qt::RoundJoin,
  Qt::BevelJoin
};
